// Copyright (c) 2023 Presto Labs Pte. Ltd.
// Author: tianqiang

#pragma once

#include <rapidjson/document.h>

#include "coin2/exchange/base/order/order.h"
#include "coin2/exchange/lbank/symbology/product.h"

namespace coin2::exchange::lbank::order_v2 {

class LbankParser : public base::order::BaseParser {
 public:
  using JsonValue = rapidjson::GenericValue<rapidjson::UTF8<>>;
  using ProductOrderBundle = coin::proto::ProductOrderBundle;
  using ProductOrderElement = coin::proto::ProductOrderElement;

 public:
  const ParseResult& ParseRawMessage(const RawMessage& msg) override;
  AccountBalance ParseBalance(const JsonValue& doc) override;

 private:
  void ParseAccountBalance();
  void ParseOpenOrderInfo();
  void ParseHistoryOrderInfo();
  void ParseFillOrderInfo();
  void ParseSubmitResponse();
  void ParseCancelResponse();
  void ParseListenKey();

  void ParseWsBalanceInfoList(const JsonDocument& document);
  void ParseWsOrderInfoList(const JsonDocument& document);
  void ParseWsTradeInfoList(const JsonDocument& document);
  void ParseWsMessage();

  void ParseOrderInfo(ProductOrderElement* order, const JsonValue& data);
  void ParseFillInfo(ProductFillElement* fill, const JsonValue& data);

  int32_t ParseErrorMessage(const std::shared_ptr<AsioHttpContext>& http_context);
  bool ParseRawBalance(const JsonValue& doc, RawBalanceMap* raw_balance_map);

 private:
  void HitRateLimit(std::string func);
  std::optional<int64_t> GetErrorCode(const JsonValue& json);
  std::string GetErrorMsg(int64_t error_code);
  std::optional<bool> GetResult(const JsonValue& json);
  coin::proto::OrderErrorCode GetOrderErrorCode(int64_t exchange_error_code);
  bool IsLbankSpotErrMessage(const JsonValue& doc);
  int64_t GetProcOrderId(const JsonValue& data);
  int64_t GetWsProcOrderId(const JsonValue& data);
  coin::proto::OrderSide GetOrderSide(const std::string& side);
  coin::proto::OrderType GetOrderType(const std::string& type);
  void SetOrderStatus(ProductOrderElement* order, const std::string& status);

  bool IsBalanceUpdate(const JsonValue& json);
  bool IsOrderUpdate(const JsonValue& json);

  void OnParseListenKeyFail();

 private:
  bool is_account_balance_initialized_ = false;
  int64_t parse_listen_key_fail_time_ = 0;
};

}  // namespace coin2::exchange::lbank::order_v2
